Datenbasis

Beschreibung im Fließtext

Hier werden R-Ausdrücke direkt in den Text eingebettet. Anwendungsbeispiel: Kontinuierliche Datenerhebung mit sich ändernden Fallzahlen. Die Zahlen im Text werden bei der Berichtserstellung automatisch aktualisiert.

Die folgenden Daten beruhen auf 3000 Alben von 1002 verschiedenen Bands / Künstlern. Sie stammen von der Webseite https://tsort.info/. Wir verwenden die Version 2-8-0044.

Interaktive Daten-Tabelle

DT::datatable(topalbums)
# Zum Ausprobieren: Argument filter; z. B. "filter = "top" oder filter = "bottom"
# DT::datatable(topalbums, filter = "xxx")

# Zum Ausprobieren: Argument options = list(pageLength = x)
# DT::datatable(topalbums, options = list(pageLength = 7))

Gruppenvergleiche

t-Test: Standard-Ausgabe

Rs Standard-Ausgabe ist nicht direkt für Publikationen verwendbar …

my_bands <- topalbums %>% 
  filter(artist %in% c("Bob Dylan", "The Beatles"))

my_test <- t.test(final_score ~ artist,
   alternative = 'two.sided',
   conf.level = .95, var.equal = FALSE,
   data = my_bands)

my_test

    Welch Two Sample t-test

data:  final_score by artist
t = -2.6999, df = 38.571, p-value = 0.01024
alternative hypothesis: true difference in means between group Bob Dylan and group The Beatles is not equal to 0
95 percent confidence interval:
 -10.54416  -1.51018
sample estimates:
  mean in group Bob Dylan mean in group The Beatles 
                 8.175923                 14.203094 

t-Test: Text-Interpretation mit report

Ergebnisse wie oben textlich fundiert und publikationsfähig zu interpretieren, ist nicht für jedeN der schönste Teil der Datenanalyse. Praktisch, wenn es einfach geht:

# R-Paket: report

report(my_test)


The Welch Two Sample t-test testing the difference of final_score by artist (mean in group Bob Dylan = 8.18, mean in group The Beatles = 14.20) suggests that the effect is negative, statistically significant, and large (difference = -6.03, 95% CI [-10.54, -1.51], t(38.57) = -2.70, p = 0.010; Cohen's d = -0.87, 95% CI [-1.52, -0.20])

t-Test: Grafische Darstellung mit ggstatsplot

# R-Paket: ggstatsplot

ggbetweenstats(my_bands,
  x = artist, y = final_score,
  title = "Gesamtpunkte im Vergleich",
  caption = "Datenquelle: tsort.info")

  • Boxplot
  • Violin-Plot
  • Einzelne Datenpunkte
  • Angereichert mit statistischen Kennzahlen

Gruppenvergleich: Tabellarisch mit gtsummary

add_p() wählt automatisch einen Test aus; hier: Wilcoxon Rank-Sum Test.

my_bands %>% 
  select(artist, final_score) %>% 
  tbl_summary(by = artist) %>% 
  add_p()
Characteristic Bob Dylan, N = 261 The Beatles, N = 321 p-value2
final_score 7 (6, 10) 9 (6, 17) 0.049
1 Median (IQR)
2 Wilcoxon rank sum exact test
# Alternative: Hier direkt die Bands ändern

topalbums %>%
  select(artist, final_score) %>% 
  filter(artist %in% c("Madonna", "Bruce Springsteen")) %>%
  tbl_summary(by = artist) %>%
  add_p()
Characteristic Bruce Springsteen, N = 211 Madonna, N = 201 p-value2
final_score 9.1 (5.7, 13.0) 10.1 (7.4, 14.9) 0.2
1 Median (IQR)
2 Wilcoxon rank sum exact test

Stattdessen t-Test vorgeben, siehe ?add_p():

topalbums %>% 
  filter(artist %in% c("Madonna", "Bruce Springsteen")) %>%
  select(artist, final_score) %>% 
  tbl_summary(by = artist) %>% 
  add_p(
    # perform t-test for all variables
    test = everything() ~ "t.test",
    # assume equal variance in the t-test
    test.args = all_tests("t.test") ~ list(var.equal = TRUE)
)
Characteristic Bruce Springsteen, N = 211 Madonna, N = 201 p-value2
final_score 9.1 (5.7, 13.0) 10.1 (7.4, 14.9) 0.5
1 Median (IQR)
2 Two Sample t-test

Gruppenvergleich: Vorschläge für andere Tests

Für Fortgeschrittene zum Üben: Andere Fragestellungen testen.

Vorschlag: Unterscheiden sich Alben, die über 5 Punkte erreicht haben, von Alben, die max. 5 Punkte erreicht haben, im durchschnittlichen Alter? Vermutung / Hypothese: Erfolgreichere Alben sind durchschnittlich älter.

Alternative Idee: Unterscheiden sich Alben, die bis zu dem einschneidenden Jahr 1990 veröffentlicht wurden, in der durchschnittlichen Gesamtpunktzahl von Alben, die nach 1990 veröffentlicht wurden?

Oder andere Bands auswählen.

Oder mit anderen Daten arbeiten: topsongs bzw. für aktuellere Musik albums2000, songs2000.

Wer mag, kann, analog zu oben, Test-Einstellungen variieren (t-Test, gleiche Varianzen annehmen ja oder nein).

# Unterscheiden sich Alben, die über 5 Punkte erreicht haben, von Alben, die max. 5 Punkte erreicht haben, im durchschnittlichen Alter?
# Vermutung / Hypothese: Erfolgreichere Alben sind durchschnittlich älter.

topalbums <- topalbums %>% 
  mutate(ueber5 = ifelse(final_score > 5, "> 5 P", "< 5 P"))

# Variable in erster Zeile einfügen
# my_test <- t.test(year ~ xxx,
#    alternative = 'greater',
#    conf.level = .95, var.equal = FALSE,
#    data = topalbums)
# 
# my_test

# Text-Interpretation: report


# Grafisch: ggstatsplot


# Tabellarisch: gtsummary

Korrelation

Standard-Ausgabe

Korrelation <- cor.test(topalbums$raw_usa,
                        topalbums$raw_eur)

Korrelation

    Pearson's product-moment correlation

data:  topalbums$raw_usa and topalbums$raw_eur
t = -3.7065, df = 2998, p-value = 0.0002139
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.10307656 -0.03182962
sample estimates:
        cor 
-0.06753919 

Text-Interpretation

report(Korrelation)


The Pearson's product-moment correlation between topalbums$raw_usa and topalbums$raw_eur is negative, statistically significant, and very small (r = -0.07, 95% CI [-0.10, -0.03], t(2998) = -3.71, p < .001)

Grafisch

ggscatterstats(data = topalbums,
    x = raw_usa, y = raw_eur)

Simple Syntax - informative Ausgabe!

  • Streudiagramm: bivariate Verteilungen
  • Dichte + Histogramm: “marginal densigram” - Verteilungen
  • Anpassungsgerade mit Konfidenzband: Linearer Zusammenhang?
  • Korrelationskoeffizient Pearson’s r
  • t-Wert, p-Wert, Konfidenzintervall für r, Fallzahl
  • Bayes Factor

Zum Üben: Bayes-Faktor verbergen

Tipp: Parameter bf.message; Voreinstellung: TRUE

# ggscatterstats(data = topalbums,
#     x = raw_usa, y = raw_eur,
#     fb.message = xxx)

Regression

  • Nimmt im Gegensatz zur Korrelation eine Wirkungsrichtung an
  • Unterscheidung zwischen unabhängigen Variablen (Prädiktoren, Regressoren) und abhängiger Variable (Zielgröße, Regressand)

Standard-Ausgabe

reg <- lm(raw_eur ~ raw_usa,
          data = topalbums)

reg

Call:
lm(formula = raw_eur ~ raw_usa, data = topalbums)

Coefficients:
(Intercept)      raw_usa  
    4.51192     -0.07867  

Hier ist das summary so programmiert, dass es eine ausführlichere Ausgabe enthält als das Regressionsobjekt selbst.

summary(reg)

Call:
lm(formula = raw_eur ~ raw_usa, data = topalbums)

Residuals:
   Min     1Q Median     3Q    Max 
-4.403 -2.923 -1.079  1.761 14.900 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  4.51192    0.11626  38.809  < 2e-16 ***
raw_usa     -0.07867    0.02122  -3.707 0.000214 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 3.793 on 2998 degrees of freedom
Multiple R-squared:  0.004562,  Adjusted R-squared:  0.00423 
F-statistic: 13.74 on 1 and 2998 DF,  p-value: 0.0002139

Text-Interpretation: report

# Zum Selbst-Ausfüllen ...

Grafische Darstellung siehe Korrelation.

Test auf Normalverteilung

Voraussetzung vieler parametrischer Verfahren wie z. B. t-Test.

Statistisch

shapiro.test(topalbums$final_score)

    Shapiro-Wilk normality test

data:  topalbums$final_score
W = 0.6974, p-value < 2.2e-16

Anregung zum Üben: Andere Variable auswählen, z. B. year oder andere Punktzahl wie raw_usa, oder anderen Datensatz verwenden (z. B. songs2000 mit indicativerevenue)

Grafisch: ggstatsplot

ggstatsplot::gghistostats(
  topalbums, final_score,
  normal.curve = TRUE)

Anregungen zum Üben:

  • Andere Effektgröße auswählen. Voreinstellung: Hedge’s g (“g”); Alternative: Cohen’s d (“d”)
# ggstatsplot::gghistostats(
#   topalbums, final_score,
#   normal.curve = TRUE,
#   effsize.type = "xxx")

Ergänzungen

Interaktive Grafiken

Ein “normales” statisches Diagramm …

Anstatt den ggplot-Befehl direkt anzuwenden, kann man das Diagramm einem Objekt zuweisen: p für plot.

Dieses können wir dann später weiterverwenden.

p <- topalbums %>% 
  filter(artist %in% c("Bob Dylan", "The Beatles", "The Rolling Stones", "Bruce Springsteen", "Madonna")) %>% 
  ggplot(aes(x = year, y = final_score, label = name, col = artist)) +
  labs(title = "Alben & Punktzahlen",
       subtitle = "Ausgewählte Bands",
       x = "Jahr", y = "Punktzahl") +
  scale_color_discrete(name = "Künstler / Band") +
  geom_point()

p

# Kurz für: print(p)

Was müssen wir tun, um dieses Diagramm interaktiv zu machen?

plotly::ggplotly(p)

Anregung zum Üben: Andere Bands auswählen; wer mag, kann einen anderen Datensatz verwenden (z. B. songs2000 oder albums2000).

Animationen mit gganimate

Code von Thomas L. Pedersen, siehe Dokumentation zu gganimate.

library(gapminder)
library(ggplot2)
library(gganimate)

ggplot(gapminder, aes(gdpPercap, lifeExp, size = pop, colour = country)) +
  geom_point(alpha = 0.7) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  scale_x_log10() +
  facet_wrap(~continent) +
  theme_bw() +
  theme(legend.position = 'none') +
  labs(title = 'Year: {frame_time}', x = 'GDP per capita', y = 'life expectancy') +
  transition_time(year)

Regressionstabellen mit texreg::htmlreg

Ein Modell:

Stones_lm <- topalbums %>% 
  filter(artist == "The Rolling Stones") %>% 
  lm(raw_eur ~ raw_usa, data = .)

htmlreg(Stones_lm, doctype = FALSE)
Statistical models
  Model 1
(Intercept) 5.45***
  (1.22)
raw_usa -0.09
  (0.18)
R2 0.01
Adj. R2 -0.02
Num. obs. 36
***p < 0.001; **p < 0.01; *p < 0.05
htmlreg(Stones_lm, single.row = TRUE, doctype = FALSE)
Statistical models
  Model 1
(Intercept) 5.45 (1.22)***
raw_usa -0.09 (0.18)
R2 0.01
Adj. R2 -0.02
Num. obs. 36
***p < 0.001; **p < 0.01; *p < 0.05

Vergleich von zwei Modellen:

Beatles_lm <- topalbums %>%
  filter(artist == "The Beatles") %>% 
  lm(raw_eur ~ raw_usa, data = .)

htmlreg(list(Stones_lm, Beatles_lm),
        custom.model.names = c("Stones", "Beatles"),
        doctype = FALSE)
Statistical models
  Stones Beatles
(Intercept) 5.45*** 3.18**
  (1.22) (1.03)
raw_usa -0.09 0.18
  (0.18) (0.09)
R2 0.01 0.12
Adj. R2 -0.02 0.09
Num. obs. 36 32
***p < 0.001; **p < 0.01; *p < 0.05

Das gt-Paket für flexibel gestaltbare Tabellen

Das gt-Paket ermöglicht sehr flexibel gestaltbare Tabellen mit relativ intuitiver Syntax.

topalbums %>% 
  head() %>% 
  gt()
position artist name year final_score raw_usa raw_eng raw_eur ueber5
1 The Beatles Sgt Pepper's Lonely Hearts Club Band 1967 54.415 33.740 13.824 9.284 > 5 P
2 Michael Jackson Thriller 1982 50.782 29.628 18.143 14.952 > 5 P
3 U2 The Joshua Tree 1987 38.197 21.342 13.411 17.733 > 5 P
4 The Beatles Abbey Road 1969 37.233 24.587 9.409 9.953 > 5 P
5 Fleetwood Mac Rumours 1977 36.616 30.057 15.097 7.300 > 5 P
6 Pink Floyd Dark Side Of The Moon 1973 35.338 26.903 13.621 9.717 > 5 P

Nehmen wir an, final_score wäre in US-Dollar - wie können wir die Zahlen einfach formatieren?

Dazu Tabellenüberschrift und Unter-Überschrift; Zellen mit raw_usa > 24 hervorgehoben.

topalbums %>%
  head() %>% 
  gt() %>% 
  fmt_currency(columns = "final_score",
               currency = "USD") %>% 
  tab_header(title = "Top Alben",
             subtitle = glue::glue("Von {min(topalbums$year)} bis {max(topalbums$year)}")) %>% 
  tab_style(
    style = list(
      cell_fill(color = "lightblue"),
      cell_text(style = "italic")
    ),
    locations = cells_body(
      columns = raw_usa,
      rows = raw_usa > 24
    )
  )
Top Alben
Von 1940 bis 2018
position artist name year final_score raw_usa raw_eng raw_eur ueber5
1 The Beatles Sgt Pepper's Lonely Hearts Club Band 1967 $54.41 33.740 13.824 9.284 > 5 P
2 Michael Jackson Thriller 1982 $50.78 29.628 18.143 14.952 > 5 P
3 U2 The Joshua Tree 1987 $38.20 21.342 13.411 17.733 > 5 P
4 The Beatles Abbey Road 1969 $37.23 24.587 9.409 9.953 > 5 P
5 Fleetwood Mac Rumours 1977 $36.62 30.057 15.097 7.300 > 5 P
6 Pink Floyd Dark Side Of The Moon 1973 $35.34 26.903 13.621 9.717 > 5 P
LS0tDQp0aXRsZTogJ0RhdGVuYW5hbHlzZSAvIFN0YXRpc3RpayBtaXQgUiBsZWljaHQgZ2VtYWNodCEnDQpzdWJ0aXRsZTogIkRhdGEgU2NpZW5jZSBNZWV0dXAgRGFybXN0YWR0Ig0KYXV0aG9yOiAiV29sZiBSaWVwbCINCmRhdGU6ICdCZXJpY2h0IGVyc3RlbGx0OiBgciBTeXMudGltZSgpYCcNCiMgb3V0cHV0OiBodG1sX2RvY3VtZW50ICAgIyBadXIgRXJ3ZWl0ZXJ1bmcgImh0bWxfZG9jdW1lbnQiIGhpZXIgbMO2c2NoZW4gdW5kIGluIG5ldWVyIFplaWxlIHZlcndlbmRlbiB3aWUgdW50ZW4NCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCg0KbGlicmFyeSh0aWR5dmVyc2UpICAgICAgICAgICAgICAgICAgICAgICAgIyBQYWtldC1TYW1tbHVuZyBtaXQgaW50dWl0aXZlciBTeW50YXggenVyIERhdGVuYmVhcmJlaXR1bmcNCmxpYnJhcnkoRFQpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSW50ZXJha3RpdmUgVGFiZWxsZW4gaW4gTWFya2Rvd24NCmxpYnJhcnkocmVwb3J0KSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVGV4dC1JbnRlcnByZXRhdGlvbiBzdGF0aXN0aXNjaGVyIE1vZGVsbGUNCmxpYnJhcnkoZ2dzdGF0c3Bsb3QpICAgICAgICAgICAgICAgICAgICAgICMgRGlhZ3JhbW1lIG1pdCBzdGF0aXN0aXNjaGVuIFp1c2F0ei1JbmZvcm1hdGlvbmVuDQpsaWJyYXJ5KGd0KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZsZXhpYmxlIFRhYmVsbGVuDQpsaWJyYXJ5KGd0c3VtbWFyeSkgICAgICAgICAgICAgICAgICAgICAgICAjIFN0YXRpc3Rpc2NoZSBUZXN0cywgdGFiZWxsYXJpc2NoDQpsaWJyYXJ5KHBsb3RseSkgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEludGVyYWt0aXZlIEdyYWZpa2VuDQpsaWJyYXJ5KHRleHJlZykgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFJlZ3Jlc3Npb25zdGFiZWxsZW4gZGFyc3RlbGxlbg0KIyBsaWJyYXJ5KGdndGhlbWVzKSAgICAgICAgICAgICAgICAgICAgICAgICAjICMgWnVzw6R0emxpY2hlIERpYWdyYW1tLVN0aWxlLCB6LiBCLiBXYWxsIFN0cmVldCBKb3VybmFsICh0aGVtZV93c2opDQoNCmxpYnJhcnkoY2hhcnRtdXNpY2RhdGEpICAgICAgICAgICAgICAgICAgICMgRGF0ZW4gw7xiZXIgQ2hhcnRlcmZvbGcgdm9uIEFsYmVuIHVuZCBTb25ncw0KZGF0YSh0b3Bzb25ncykNCmRhdGEodG9wYWxidW1zKQ0KDQojIFNwYWx0ZSAicmF3X3JvdyIgZW50ZmVybmVuIGbDvHIgw7xiZXJzaWNodGxpY2hlcmUgRGFyc3RlbGx1bmdlbg0KDQp0b3BhbGJ1bXMgPC0gdG9wYWxidW1zICU+JSANCiAgc2VsZWN0KC1yYXdfcm93KQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpICAgICAgICAjIFItQ29kZWJsw7Zja2UgYW56ZWlnZW4sIHdlbm4gbmljaHQgYW5kZXJzIGFuZ2VnZWJlbg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gVFJVRSkgICAgICAgIyBFcmdlYm5pc3NlIGRlciBDb2RlYmzDtmNrZSBjYWNoZW4gZsO8ciBzY2huZWxsZXJlIEF1c2bDvGhydW5nDQprbml0cjo6b3B0c19jaHVuayRzZXQoY29tbWVudCA9IE5BKSAgICAgICAjIEVyZ2Vibmlzc2UgbmljaHQgbWl0ICMjIGVpbmJldHRlbiwgc29uZGVybiBkaXJla3QgLSBzaWVodCBiZXNzZXIgYXVzDQoNCmBgYA0KDQojIERhdGVuYmFzaXMNCg0KIyMgQmVzY2hyZWlidW5nIGltIEZsaWXDn3RleHQNCg0KKkhpZXIgd2VyZGVuIFItQXVzZHLDvGNrZSBkaXJla3QgaW4gZGVuIFRleHQgZWluZ2ViZXR0ZXQuIEFud2VuZHVuZ3NiZWlzcGllbDogS29udGludWllcmxpY2hlIERhdGVuZXJoZWJ1bmcgbWl0IHNpY2ggw6RuZGVybmRlbiBGYWxsemFobGVuLiBEaWUgWmFobGVuIGltIFRleHQgd2VyZGVuIGJlaSBkZXIgQmVyaWNodHNlcnN0ZWxsdW5nIGF1dG9tYXRpc2NoIGFrdHVhbGlzaWVydC4qDQoNCkRpZSBmb2xnZW5kZW4gRGF0ZW4gYmVydWhlbiBhdWYgYHIgbnJvdyh0b3BhbGJ1bXMpYCBBbGJlbiB2b24gYHIgbGVuZ3RoKHVuaXF1ZSh0b3BhbGJ1bXMkYXJ0aXN0KSlgIHZlcnNjaGllZGVuZW4gQmFuZHMgLyBLw7xuc3RsZXJuLiBTaWUgc3RhbW1lbiB2b24gZGVyIFdlYnNlaXRlIGh0dHBzOi8vdHNvcnQuaW5mby8uIFdpciB2ZXJ3ZW5kZW4gZGllIFZlcnNpb24gKipgciBhdHRyKHRvcGFsYnVtcywgInZlcnNpb24iKWAqKi4NCg0KDQojIyBJbnRlcmFrdGl2ZSBEYXRlbi1UYWJlbGxlDQoNCmBgYHtyIERhdGVuLVRhYmVsbGV9DQpEVDo6ZGF0YXRhYmxlKHRvcGFsYnVtcykNCg0KIyBadW0gQXVzcHJvYmllcmVuOiBBcmd1bWVudCBmaWx0ZXI7IHouIEIuICJmaWx0ZXIgPSAidG9wIiBvZGVyIGZpbHRlciA9ICJib3R0b20iDQojIERUOjpkYXRhdGFibGUodG9wYWxidW1zLCBmaWx0ZXIgPSAieHh4IikNCg0KIyBadW0gQXVzcHJvYmllcmVuOiBBcmd1bWVudCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0geCkNCiMgRFQ6OmRhdGF0YWJsZSh0b3BhbGJ1bXMsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA3KSkNCg0KYGBgDQoNCg0KIyBHcnVwcGVudmVyZ2xlaWNoZQ0KDQojIyB0LVRlc3Q6IFN0YW5kYXJkLUF1c2dhYmUNCg0KUnMgU3RhbmRhcmQtQXVzZ2FiZSBpc3QgbmljaHQgZGlyZWt0IGbDvHIgUHVibGlrYXRpb25lbiB2ZXJ3ZW5kYmFyIC4uLg0KDQpgYGB7ciB0dGVzdH0NCg0KbXlfYmFuZHMgPC0gdG9wYWxidW1zICU+JSANCiAgZmlsdGVyKGFydGlzdCAlaW4lIGMoIkJvYiBEeWxhbiIsICJUaGUgQmVhdGxlcyIpKQ0KDQpteV90ZXN0IDwtIHQudGVzdChmaW5hbF9zY29yZSB+IGFydGlzdCwNCiAgIGFsdGVybmF0aXZlID0gJ3R3by5zaWRlZCcsDQogICBjb25mLmxldmVsID0gLjk1LCB2YXIuZXF1YWwgPSBGQUxTRSwNCiAgIGRhdGEgPSBteV9iYW5kcykNCg0KbXlfdGVzdA0KDQpgYGANCg0KDQojIyMgdC1UZXN0OiBUZXh0LUludGVycHJldGF0aW9uIG1pdCAqcmVwb3J0Kg0KDQpFcmdlYm5pc3NlIHdpZSBvYmVuIHRleHRsaWNoIGZ1bmRpZXJ0IHVuZCBwdWJsaWthdGlvbnNmw6RoaWcgenUgaW50ZXJwcmV0aWVyZW4sIGlzdCBuaWNodCBmw7xyIGplZGVOIGRlciBzY2jDtm5zdGUgVGVpbCBkZXIgRGF0ZW5hbmFseXNlLiBQcmFrdGlzY2gsIHdlbm4gZXMgZWluZmFjaCBnZWh0Og0KDQpgYGB7ciB0dGVzdC1yZXBvcnQsIHdhcm5pbmcgPSBGQUxTRX0NCiMgUi1QYWtldDogcmVwb3J0DQoNCnJlcG9ydChteV90ZXN0KQ0KDQpgYGANCg0KDQojIyMgdC1UZXN0OiBHcmFmaXNjaGUgRGFyc3RlbGx1bmcgbWl0ICpnZ3N0YXRzcGxvdCoNCg0KYGBge3IgdHRlc3QtZ2dzdGF0c3Bsb3R9DQojIFItUGFrZXQ6IGdnc3RhdHNwbG90DQoNCmdnYmV0d2VlbnN0YXRzKG15X2JhbmRzLA0KICB4ID0gYXJ0aXN0LCB5ID0gZmluYWxfc2NvcmUsDQogIHRpdGxlID0gIkdlc2FtdHB1bmt0ZSBpbSBWZXJnbGVpY2giLA0KICBjYXB0aW9uID0gIkRhdGVucXVlbGxlOiB0c29ydC5pbmZvIikNCmBgYA0KDQoqIEJveHBsb3QNCiogVmlvbGluLVBsb3QNCiogRWluemVsbmUgRGF0ZW5wdW5rdGUNCiogQW5nZXJlaWNoZXJ0IG1pdCBzdGF0aXN0aXNjaGVuIEtlbm56YWhsZW4NCg0KDQojIyBHcnVwcGVudmVyZ2xlaWNoOiBUYWJlbGxhcmlzY2ggbWl0ICpndHN1bW1hcnkqDQoNCiphZGRfcCgpKiB3w6RobHQgYXV0b21hdGlzY2ggZWluZW4gVGVzdCBhdXM7IGhpZXI6IFdpbGNveG9uIFJhbmstU3VtIFRlc3QuDQoNCmBgYHtyIGdydXBwZW52ZXJnbGVpY2gtZ3RzdW1tYXJ5fQ0KDQpteV9iYW5kcyAlPiUgDQogIHNlbGVjdChhcnRpc3QsIGZpbmFsX3Njb3JlKSAlPiUgDQogIHRibF9zdW1tYXJ5KGJ5ID0gYXJ0aXN0KSAlPiUgDQogIGFkZF9wKCkNCg0KDQojIEFsdGVybmF0aXZlOiBIaWVyIGRpcmVrdCBkaWUgQmFuZHMgw6RuZGVybg0KDQp0b3BhbGJ1bXMgJT4lDQogIHNlbGVjdChhcnRpc3QsIGZpbmFsX3Njb3JlKSAlPiUgDQogIGZpbHRlcihhcnRpc3QgJWluJSBjKCJNYWRvbm5hIiwgIkJydWNlIFNwcmluZ3N0ZWVuIikpICU+JQ0KICB0Ymxfc3VtbWFyeShieSA9IGFydGlzdCkgJT4lDQogIGFkZF9wKCkNCg0KYGBgDQoNCiAgDQpTdGF0dGRlc3NlbiB0LVRlc3Qgdm9yZ2ViZW4sIHNpZWhlICo/YWRkX3AoKSo6DQoNCmBgYHtyIHR0ZXN0LWd0c3VtbWFyeX0NCg0KdG9wYWxidW1zICU+JSANCiAgZmlsdGVyKGFydGlzdCAlaW4lIGMoIk1hZG9ubmEiLCAiQnJ1Y2UgU3ByaW5nc3RlZW4iKSkgJT4lDQogIHNlbGVjdChhcnRpc3QsIGZpbmFsX3Njb3JlKSAlPiUgDQogIHRibF9zdW1tYXJ5KGJ5ID0gYXJ0aXN0KSAlPiUgDQogIGFkZF9wKA0KICAgICMgcGVyZm9ybSB0LXRlc3QgZm9yIGFsbCB2YXJpYWJsZXMNCiAgICB0ZXN0ID0gZXZlcnl0aGluZygpIH4gInQudGVzdCIsDQogICAgIyBhc3N1bWUgZXF1YWwgdmFyaWFuY2UgaW4gdGhlIHQtdGVzdA0KICAgIHRlc3QuYXJncyA9IGFsbF90ZXN0cygidC50ZXN0IikgfiBsaXN0KHZhci5lcXVhbCA9IFRSVUUpDQopDQoNCmBgYA0KDQoNCiMjIEdydXBwZW52ZXJnbGVpY2g6IFZvcnNjaGzDpGdlIGbDvHIgYW5kZXJlIFRlc3RzDQoNCkbDvHIgRm9ydGdlc2Nocml0dGVuZSB6dW0gw5xiZW46IEFuZGVyZSBGcmFnZXN0ZWxsdW5nZW4gdGVzdGVuLg0KDQpWb3JzY2hsYWc6IFVudGVyc2NoZWlkZW4gc2ljaCBBbGJlbiwgZGllIMO8YmVyIDUgUHVua3RlIGVycmVpY2h0IGhhYmVuLCB2b24gQWxiZW4sIGRpZSBtYXguIDUgUHVua3RlIGVycmVpY2h0IGhhYmVuLCBpbSBkdXJjaHNjaG5pdHRsaWNoZW4gQWx0ZXI/DQpWZXJtdXR1bmcgLyBIeXBvdGhlc2U6IEVyZm9sZ3JlaWNoZXJlIEFsYmVuIHNpbmQgZHVyY2hzY2huaXR0bGljaCDDpGx0ZXIuDQoNCkFsdGVybmF0aXZlIElkZWU6IFVudGVyc2NoZWlkZW4gc2ljaCBBbGJlbiwgZGllIGJpcyB6dSBkZW0gZWluc2NobmVpZGVuZGVuIEphaHIgMTk5MCB2ZXLDtmZmZW50bGljaHQgd3VyZGVuLCBpbiBkZXIgZHVyY2hzY2huaXR0bGljaGVuIEdlc2FtdHB1bmt0emFobCB2b24gQWxiZW4sIGRpZSBuYWNoIDE5OTAgdmVyw7ZmZmVudGxpY2h0IHd1cmRlbj8NCg0KT2RlciBhbmRlcmUgQmFuZHMgYXVzd8OkaGxlbi4NCg0KT2RlciBtaXQgYW5kZXJlbiBEYXRlbiBhcmJlaXRlbjogKioqdG9wc29uZ3MqKiogYnp3LiBmw7xyIGFrdHVlbGxlcmUgTXVzaWsgKioqYWxidW1zMjAwMCwgc29uZ3MyMDAwKioqLg0KDQpXZXIgbWFnLCBrYW5uLCBhbmFsb2cgenUgb2JlbiwgVGVzdC1FaW5zdGVsbHVuZ2VuIHZhcmlpZXJlbiAodC1UZXN0LCBnbGVpY2hlIFZhcmlhbnplbiBhbm5laG1lbiBqYSBvZGVyIG5laW4pLg0KDQpgYGB7ciB0dGVzdC1hbHRlcm5hdGl2ZW59DQoNCiMgVW50ZXJzY2hlaWRlbiBzaWNoIEFsYmVuLCBkaWUgw7xiZXIgNSBQdW5rdGUgZXJyZWljaHQgaGFiZW4sIHZvbiBBbGJlbiwgZGllIG1heC4gNSBQdW5rdGUgZXJyZWljaHQgaGFiZW4sIGltIGR1cmNoc2Nobml0dGxpY2hlbiBBbHRlcj8NCiMgVmVybXV0dW5nIC8gSHlwb3RoZXNlOiBFcmZvbGdyZWljaGVyZSBBbGJlbiBzaW5kIGR1cmNoc2Nobml0dGxpY2ggw6RsdGVyLg0KDQp0b3BhbGJ1bXMgPC0gdG9wYWxidW1zICU+JSANCiAgbXV0YXRlKHVlYmVyNSA9IGlmZWxzZShmaW5hbF9zY29yZSA+IDUsICI+IDUgUCIsICI8IDUgUCIpKQ0KDQojIFZhcmlhYmxlIGluIGVyc3RlciBaZWlsZSBlaW5mw7xnZW4NCiMgbXlfdGVzdCA8LSB0LnRlc3QoeWVhciB+IHh4eCwNCiMgICAgYWx0ZXJuYXRpdmUgPSAnZ3JlYXRlcicsDQojICAgIGNvbmYubGV2ZWwgPSAuOTUsIHZhci5lcXVhbCA9IEZBTFNFLA0KIyAgICBkYXRhID0gdG9wYWxidW1zKQ0KIyANCiMgbXlfdGVzdA0KDQojIFRleHQtSW50ZXJwcmV0YXRpb246IHJlcG9ydA0KDQoNCiMgR3JhZmlzY2g6IGdnc3RhdHNwbG90DQoNCg0KIyBUYWJlbGxhcmlzY2g6IGd0c3VtbWFyeQ0KDQoNCmBgYA0KDQoNCg0KIyBLb3JyZWxhdGlvbg0KDQojIyBTdGFuZGFyZC1BdXNnYWJlDQoNCmBgYHtyIGtvcnItc3RhbmRhcmR9DQoNCktvcnJlbGF0aW9uIDwtIGNvci50ZXN0KHRvcGFsYnVtcyRyYXdfdXNhLA0KICAgICAgICAgICAgICAgICAgICAgICAgdG9wYWxidW1zJHJhd19ldXIpDQoNCktvcnJlbGF0aW9uDQpgYGANCg0KDQojIyBUZXh0LUludGVycHJldGF0aW9uDQoNCmBgYHtyIGtvcnItcmVwb3J0fQ0KcmVwb3J0KEtvcnJlbGF0aW9uKQ0KYGBgDQoNCg0KIyMgR3JhZmlzY2gNCg0KYGBge3Iga29yci1nZ3N0YXRzcGxvdCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQoNCmdnc2NhdHRlcnN0YXRzKGRhdGEgPSB0b3BhbGJ1bXMsDQogICAgeCA9IHJhd191c2EsIHkgPSByYXdfZXVyKQ0KDQpgYGANCg0KKipTaW1wbGUgU3ludGF4IC0gaW5mb3JtYXRpdmUgQXVzZ2FiZSEqKg0KDQoqIFN0cmV1ZGlhZ3JhbW06IGJpdmFyaWF0ZSBWZXJ0ZWlsdW5nZW4NCiogRGljaHRlICsgSGlzdG9ncmFtbTogIm1hcmdpbmFsIGRlbnNpZ3JhbSIgLSBWZXJ0ZWlsdW5nZW4NCiogQW5wYXNzdW5nc2dlcmFkZSBtaXQgS29uZmlkZW56YmFuZDogTGluZWFyZXIgWnVzYW1tZW5oYW5nPw0KKiBLb3JyZWxhdGlvbnNrb2VmZml6aWVudCBQZWFyc29uJ3Mgcg0KKiB0LVdlcnQsIHAtV2VydCwgS29uZmlkZW56aW50ZXJ2YWxsIGbDvHIgciwgRmFsbHphaGwNCiogQmF5ZXMgRmFjdG9yDQoNClp1bSDDnGJlbjogQmF5ZXMtRmFrdG9yIHZlcmJlcmdlbg0KDQpUaXBwOiBQYXJhbWV0ZXIgKmJmLm1lc3NhZ2UqOyBWb3JlaW5zdGVsbHVuZzogVFJVRQ0KDQpgYGB7ciBrb3JyLWdnc3RhdHNwbG90LWF1ZmdhYmV9DQoNCiMgZ2dzY2F0dGVyc3RhdHMoZGF0YSA9IHRvcGFsYnVtcywNCiMgICAgIHggPSByYXdfdXNhLCB5ID0gcmF3X2V1ciwNCiMgICAgIGZiLm1lc3NhZ2UgPSB4eHgpDQoNCmBgYA0KDQoNCiMgUmVncmVzc2lvbg0KDQoqIE5pbW10IGltIEdlZ2Vuc2F0eiB6dXIgS29ycmVsYXRpb24gZWluZSBXaXJrdW5nc3JpY2h0dW5nIGFuDQoqIFVudGVyc2NoZWlkdW5nIHp3aXNjaGVuIHVuYWJow6RuZ2lnZW4gVmFyaWFibGVuIChQcsOkZGlrdG9yZW4sIFJlZ3Jlc3NvcmVuKSB1bmQgYWJow6RuZ2lnZXIgVmFyaWFibGUgKFppZWxncsO2w59lLCBSZWdyZXNzYW5kKQ0KDQojIyBTdGFuZGFyZC1BdXNnYWJlDQoNCmBgYHtyIHJlZy1zdGFuZGFyZH0NCg0KcmVnIDwtIGxtKHJhd19ldXIgfiByYXdfdXNhLA0KICAgICAgICAgIGRhdGEgPSB0b3BhbGJ1bXMpDQoNCnJlZw0KYGBgDQoNCkhpZXIgaXN0IGRhcyAqc3VtbWFyeSogc28gcHJvZ3JhbW1pZXJ0LCBkYXNzIGVzIGVpbmUgYXVzZsO8aHJsaWNoZXJlIEF1c2dhYmUgZW50aMOkbHQgYWxzIGRhcyBSZWdyZXNzaW9uc29iamVrdCBzZWxic3QuDQoNCmBgYHtyIHJlZy1zdW1tYXJ5fQ0Kc3VtbWFyeShyZWcpDQpgYGANCg0KDQojIyBUZXh0LUludGVycHJldGF0aW9uOiByZXBvcnQNCg0KYGBge3IgcmVnLXJlcG9ydH0NCiMgWnVtIFNlbGJzdC1BdXNmw7xsbGVuIC4uLg0KDQpgYGANCg0KR3JhZmlzY2hlIERhcnN0ZWxsdW5nIHNpZWhlIEtvcnJlbGF0aW9uLg0KDQoNCiMgVGVzdCBhdWYgTm9ybWFsdmVydGVpbHVuZw0KDQpWb3JhdXNzZXR6dW5nIHZpZWxlciBwYXJhbWV0cmlzY2hlciBWZXJmYWhyZW4gd2llIHouIEIuIHQtVGVzdC4NCg0KIyMgU3RhdGlzdGlzY2gNCg0KYGBge3IgbnZ0ZXN0LXNoYXBpcm99DQpzaGFwaXJvLnRlc3QodG9wYWxidW1zJGZpbmFsX3Njb3JlKQ0KYGBgDQoNCkFucmVndW5nIHp1bSDDnGJlbjogQW5kZXJlIFZhcmlhYmxlIGF1c3fDpGhsZW4sIHouIEIuICp5ZWFyKiBvZGVyIGFuZGVyZSBQdW5rdHphaGwgd2llICpyYXdfdXNhKiwgb2RlciBhbmRlcmVuIERhdGVuc2F0eiB2ZXJ3ZW5kZW4gKHouIEIuICpzb25nczIwMDAqIG1pdCAqaW5kaWNhdGl2ZXJldmVudWUqKQ0KDQoNCiMjIEdyYWZpc2NoOiBnZ3N0YXRzcGxvdA0KDQpgYGB7ciBudnRlc3QtZ2dzdGF0c3Bsb3R9DQoNCmdnc3RhdHNwbG90OjpnZ2hpc3Rvc3RhdHMoDQogIHRvcGFsYnVtcywgZmluYWxfc2NvcmUsDQogIG5vcm1hbC5jdXJ2ZSA9IFRSVUUpDQoNCmBgYA0KDQpBbnJlZ3VuZ2VuIHp1bSDDnGJlbjoNCg0KKiBBbmRlcmUgRWZmZWt0Z3LDtsOfZSBhdXN3w6RobGVuLiBWb3JlaW5zdGVsbHVuZzogSGVkZ2UncyBnICgiZyIpOyBBbHRlcm5hdGl2ZTogQ29oZW4ncyBkICgiZCIpDQoNCmBgYHtyIG52dGVzdC1nZ3N0YXRzcGxvdC1hdWZnYWJlfQ0KDQojIGdnc3RhdHNwbG90OjpnZ2hpc3Rvc3RhdHMoDQojICAgdG9wYWxidW1zLCBmaW5hbF9zY29yZSwNCiMgICBub3JtYWwuY3VydmUgPSBUUlVFLA0KIyAgIGVmZnNpemUudHlwZSA9ICJ4eHgiKQ0KDQpgYGANCg0KDQojIEVyZ8Okbnp1bmdlbg0KDQojIyBJbnRlcmFrdGl2ZSBHcmFmaWtlbg0KDQpFaW4gIm5vcm1hbGVzIiBzdGF0aXNjaGVzIERpYWdyYW1tIC4uLg0KDQpBbnN0YXR0IGRlbiBnZ3Bsb3QtQmVmZWhsIGRpcmVrdCBhbnp1d2VuZGVuLCBrYW5uIG1hbiBkYXMgRGlhZ3JhbW0gZWluZW0gT2JqZWt0IHp1d2Vpc2VuOiBwIGbDvHIgcGxvdC4NCg0KRGllc2VzIGvDtm5uZW4gd2lyIGRhbm4gc3DDpHRlciB3ZWl0ZXJ2ZXJ3ZW5kZW4uDQoNCmBgYHtyIGdncGxvdC1zdGF0aXNjaH0NCg0KcCA8LSB0b3BhbGJ1bXMgJT4lIA0KICBmaWx0ZXIoYXJ0aXN0ICVpbiUgYygiQm9iIER5bGFuIiwgIlRoZSBCZWF0bGVzIiwgIlRoZSBSb2xsaW5nIFN0b25lcyIsICJCcnVjZSBTcHJpbmdzdGVlbiIsICJNYWRvbm5hIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGZpbmFsX3Njb3JlLCBsYWJlbCA9IG5hbWUsIGNvbCA9IGFydGlzdCkpICsNCiAgbGFicyh0aXRsZSA9ICJBbGJlbiAmIFB1bmt0emFobGVuIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJBdXNnZXfDpGhsdGUgQmFuZHMiLA0KICAgICAgIHggPSAiSmFociIsIHkgPSAiUHVua3R6YWhsIikgKw0KICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIkvDvG5zdGxlciAvIEJhbmQiKSArDQogIGdlb21fcG9pbnQoKQ0KDQpwDQojIEt1cnogZsO8cjogcHJpbnQocCkNCg0KYGBgDQoNCldhcyBtw7xzc2VuIHdpciB0dW4sIHVtIGRpZXNlcyBEaWFncmFtbSBpbnRlcmFrdGl2IHp1IG1hY2hlbj8NCg0KYGBge3IgcGxvdGx5fQ0KcGxvdGx5OjpnZ3Bsb3RseShwKQ0KYGBgDQoNCkFucmVndW5nIHp1bSDDnGJlbjogQW5kZXJlIEJhbmRzIGF1c3fDpGhsZW47IHdlciBtYWcsIGthbm4gZWluZW4gYW5kZXJlbiBEYXRlbnNhdHogdmVyd2VuZGVuICh6LiBCLiBzb25nczIwMDAgb2RlciBhbGJ1bXMyMDAwKS4NCg0KDQojIyBBbmltYXRpb25lbiBtaXQgZ2dhbmltYXRlDQoNCkNvZGUgdm9uIFRob21hcyBMLiBQZWRlcnNlbiwgc2llaGUgRG9rdW1lbnRhdGlvbiB6dSBnZ2FuaW1hdGUuDQoNCmBgYHtyIGFuaW1hdGlvbn0NCg0KbGlicmFyeShnYXBtaW5kZXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnYW5pbWF0ZSkNCg0KZ2dwbG90KGdhcG1pbmRlciwgYWVzKGdkcFBlcmNhcCwgbGlmZUV4cCwgc2l6ZSA9IHBvcCwgY29sb3VyID0gY291bnRyeSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNykgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvdW50cnlfY29sb3JzKSArDQogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDIsIDEyKSkgKw0KICBzY2FsZV94X2xvZzEwKCkgKw0KICBmYWNldF93cmFwKH5jb250aW5lbnQpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykgKw0KICBsYWJzKHRpdGxlID0gJ1llYXI6IHtmcmFtZV90aW1lfScsIHggPSAnR0RQIHBlciBjYXBpdGEnLCB5ID0gJ2xpZmUgZXhwZWN0YW5jeScpICsNCiAgdHJhbnNpdGlvbl90aW1lKHllYXIpDQoNCmBgYA0KDQoNCiMjIFJlZ3Jlc3Npb25zdGFiZWxsZW4gbWl0IHRleHJlZzo6aHRtbHJlZw0KDQpFaW4gTW9kZWxsOg0KDQpgYGB7ciBSZWdyZXNzaW9uX1N0b25lc190ZXhyZWcsIHJlc3VsdHMgPSAnYXNpcyd9DQoNClN0b25lc19sbSA8LSB0b3BhbGJ1bXMgJT4lIA0KICBmaWx0ZXIoYXJ0aXN0ID09ICJUaGUgUm9sbGluZyBTdG9uZXMiKSAlPiUgDQogIGxtKHJhd19ldXIgfiByYXdfdXNhLCBkYXRhID0gLikNCg0KaHRtbHJlZyhTdG9uZXNfbG0sIGRvY3R5cGUgPSBGQUxTRSkNCmh0bWxyZWcoU3RvbmVzX2xtLCBzaW5nbGUucm93ID0gVFJVRSwgZG9jdHlwZSA9IEZBTFNFKQ0KYGBgDQoNClZlcmdsZWljaCB2b24gendlaSBNb2RlbGxlbjoNCg0KYGBge3IgUmVncmVzc2lvbl9jb21wYXJpc29uX3RleHJlZywgcmVzdWx0cyA9ICdhc2lzJ30NCkJlYXRsZXNfbG0gPC0gdG9wYWxidW1zICU+JQ0KICBmaWx0ZXIoYXJ0aXN0ID09ICJUaGUgQmVhdGxlcyIpICU+JSANCiAgbG0ocmF3X2V1ciB+IHJhd191c2EsIGRhdGEgPSAuKQ0KDQpodG1scmVnKGxpc3QoU3RvbmVzX2xtLCBCZWF0bGVzX2xtKSwNCiAgICAgICAgY3VzdG9tLm1vZGVsLm5hbWVzID0gYygiU3RvbmVzIiwgIkJlYXRsZXMiKSwNCiAgICAgICAgZG9jdHlwZSA9IEZBTFNFKQ0KYGBgDQoNCg0KIyMgRGFzIGd0LVBha2V0IGbDvHIgZmxleGliZWwgZ2VzdGFsdGJhcmUgVGFiZWxsZW4NCg0KRGFzICoqZ3QtUGFrZXQqKiBlcm3DtmdsaWNodCBzZWhyIGZsZXhpYmVsIGdlc3RhbHRiYXJlIFRhYmVsbGVuIG1pdCByZWxhdGl2IGludHVpdGl2ZXIgU3ludGF4Lg0KDQpgYGB7ciBndDF9DQoNCnRvcGFsYnVtcyAlPiUgDQogIGhlYWQoKSAlPiUgDQogIGd0KCkNCg0KYGBgDQoNCk5laG1lbiB3aXIgYW4sIGZpbmFsX3Njb3JlIHfDpHJlIGluIFVTLURvbGxhciAtIHdpZSBrw7ZubmVuIHdpciBkaWUgWmFobGVuIGVpbmZhY2ggZm9ybWF0aWVyZW4/DQoNCkRhenUgVGFiZWxsZW7DvGJlcnNjaHJpZnQgdW5kIFVudGVyLcOcYmVyc2NocmlmdDsgWmVsbGVuIG1pdCByYXdfdXNhID4gMjQgaGVydm9yZ2Vob2Jlbi4NCg0KYGBge3IgZ3QyfQ0KDQp0b3BhbGJ1bXMgJT4lDQogIGhlYWQoKSAlPiUgDQogIGd0KCkgJT4lIA0KICBmbXRfY3VycmVuY3koY29sdW1ucyA9ICJmaW5hbF9zY29yZSIsDQogICAgICAgICAgICAgICBjdXJyZW5jeSA9ICJVU0QiKSAlPiUgDQogIHRhYl9oZWFkZXIodGl0bGUgPSAiVG9wIEFsYmVuIiwNCiAgICAgICAgICAgICBzdWJ0aXRsZSA9IGdsdWU6OmdsdWUoIlZvbiB7bWluKHRvcGFsYnVtcyR5ZWFyKX0gYmlzIHttYXgodG9wYWxidW1zJHllYXIpfSIpKSAlPiUgDQogIHRhYl9zdHlsZSgNCiAgICBzdHlsZSA9IGxpc3QoDQogICAgICBjZWxsX2ZpbGwoY29sb3IgPSAibGlnaHRibHVlIiksDQogICAgICBjZWxsX3RleHQoc3R5bGUgPSAiaXRhbGljIikNCiAgICApLA0KICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoDQogICAgICBjb2x1bW5zID0gcmF3X3VzYSwNCiAgICAgIHJvd3MgPSByYXdfdXNhID4gMjQNCiAgICApDQogICkNCg0KYGBgDQo=